#include "apdu_rsa_manager.h"

#include "../../mk_lib/mk_utility.h"

#include <string.h>
#include <memory.h>
#include <stdlib.h>

#define MAX_RSA_TIMEOUT  30*1000

apdu_rsa_manager::apdu_rsa_manager(void)
{
}

apdu_rsa_manager::~apdu_rsa_manager(void)
{
}

apdu * apdu_rsa_manager::create_apdu_gen_rsa_keypair( int app_id, int container_id, int modulus_len )
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0x80, 0x54, 0x00,0x00, "GenRSAKeyPair");
	newApdu->set_comm_timeout(MAX_RSA_TIMEOUT);

	unsigned char data[4096] = {0};
	
	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(modulus_len, data + pos);
	pos += 2;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_import_rsa_keypair_head( int app_id, int container_id, unsigned long sym_alg_id, 
														unsigned long wrap_key_len, unsigned char * wrap_key, 
														unsigned long key_bits_len, 
														unsigned long encrypted_data_len)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_3_EXT, 0x80, 0x56, 0x00,0x00, "ImportRSAKeyPair");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	mk_utility::fill_buff_with_dword_value_be(sym_alg_id, data + pos);
	pos += 4;
	
	mk_utility::fill_buff_with_dword_value_be(wrap_key_len, data + pos);
	pos += 4;

	memcpy(data + pos, wrap_key, wrap_key_len);
	pos += wrap_key_len;

	mk_utility::fill_buff_with_dword_value_be(key_bits_len, data + pos);
	pos += 4;

	mk_utility::fill_buff_with_dword_value_be(encrypted_data_len, data + pos);
	pos += 4;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}


apdu * apdu_rsa_manager::create_apdu_rsa_sign_data( int app_id, int container_id, int input_mode, 
												   int hash_algo, unsigned char * input_data, int data_len )
{
	apdu * newApdu = new apdu(SC_APDU_CASE_3_EXT, 0x80, 0x58, input_mode, hash_algo, "RSASignData");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	memcpy(data + pos, input_data, data_len);
	pos += data_len;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}


apdu * apdu_rsa_manager::create_apdu_rsa_verify(int input_mode, int hash_algo, 
												unsigned char * pub_key_blob, int pub_key_len,
												unsigned char * input_data, unsigned long  data_len, 
												unsigned char * signature, int  sig_len )
{
	apdu * newApdu = new apdu(SC_APDU_CASE_3_EXT, 0x80, 0x5e, input_mode, hash_algo, "RSAVerify");

	unsigned char data[4096] = {0};
	int pos = 0;
	
	memcpy(data, pub_key_blob, pub_key_len);
	pos += pub_key_len;

	mk_utility::fill_buff_with_dword_value_be(data_len, data + pos);
	pos += 4;

	memcpy(data + pos, input_data, data_len);
	pos += data_len;

	mk_utility::fill_buff_with_word_value_be((unsigned short)sig_len, data + pos);
	pos += 2; 

	memcpy(data + pos, signature, sig_len);
	pos += sig_len;

	newApdu->set_lc_data(data, pos);

	return newApdu;

}

apdu * apdu_rsa_manager::create_apdu_rsa_export_session_key( int app_id, int container_id, unsigned long alg_id,
															unsigned char * pub_key_blob, unsigned long pub_key_len )
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0x80, 0x5A, 0, 0, "RSAExportSessionKey");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	mk_utility::fill_buff_with_dword_value_be(alg_id, data + pos);
	pos += 4;
	
	memcpy(data + pos, pub_key_blob, pub_key_len);
	pos += pub_key_len;

	newApdu->set_lc_data(data, pos);

	return newApdu;

}

apdu * apdu_rsa_manager::create_apdu_rsa_export_session_key_ex( int app_id, int container_id, int session_key_id, 
															   unsigned char * pub_key_blob, int pub_key_len )
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0x80, 0x5C, 0, 0, "RSAExportSessionKeyEx");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(session_key_id, data + pos);
	pos += 2;

	memcpy(data + pos, pub_key_blob, pub_key_len);
	pos += pub_key_len;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_ext_rsa_pubkey_operation( unsigned char * pub_key_blob, int pub_key_len,
															  unsigned char * input_data, int data_len )
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0x80, 0x60, 0, 0, "ExRSAPubKeyOperation");

	unsigned char data[4096] = {0};

	int pos = 0;
	memcpy(data, pub_key_blob, pub_key_len);
	pos += pub_key_len;

	mk_utility::fill_buff_with_dword_value_be(data_len, data + pos);
	pos += 4;

	memcpy(data + pos, input_data, data_len);
	pos += data_len;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_ext_rsa_encrypt(unsigned char * pub_key_blob, int pub_key_len,
								   unsigned char * input_data, int data_len)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0x80, 0x60, 0x01, 0, "ExRSAPubKeyEncrypt");

	unsigned char data[4096] = {0};

	int pos = 0;
	memcpy(data, pub_key_blob, pub_key_len);
	pos += pub_key_len;

	mk_utility::fill_buff_with_dword_value_be(data_len, data + pos);
	pos += 4;

	memcpy(data + pos, input_data, data_len);
	pos += data_len;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}



apdu * apdu_rsa_manager::create_apdu_rsa_public(int app_id, int container_id, int key_spec, 
							  unsigned char * input_data, int data_len)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0xC0, 0x14, key_spec, 0, "RSAPublic");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	memcpy(data + pos, input_data, data_len);
	pos += data_len;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_rsa_private(int app_id, int container_id, int key_spec, 
							   unsigned char * input_data, int data_len)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0xC0, 0x16, key_spec, 0, "RSAPrivate");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	memcpy(data + pos, input_data, data_len);
	pos += data_len;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_rsa_encrypt(int app_id, int container_id, int key_spec, 
							   unsigned char * input_data, int data_len)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0xC0, 0x18, key_spec, 0, "RSAEncrypt");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	memcpy(data + pos, input_data, data_len);
	pos += data_len;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_rsa_decrypt(int app_id, int container_id, int key_spec, 
							   unsigned char * input_data, int data_len)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0xC0, 0x1A, key_spec, 0, "RSADecrypt");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	memcpy(data + pos, input_data, data_len);
	pos += data_len;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_rsa_sign_ex(int app_id, int container_id, int key_spec, int hash_algo,
							   unsigned char * input_data, int data_len)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0xC0, 0x1C, key_spec, hash_algo, "RSASignEx");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	memcpy(data + pos, input_data, data_len);
	pos += data_len;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_rsa_sign_interactive(int app_id, int container_id, int key_spec, int hash_algo,int timeout,
												 unsigned char * input_data, int data_len)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0xC0, 0xA0, key_spec, hash_algo, "RSASignInteractive");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(timeout, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(app_id, data + pos);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	memcpy(data + pos, input_data, data_len);
	pos += data_len;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_rsa_sign_interactive_cancel(int app_id, int container_id, int key_spec, int hash_algo)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_1, 0xC0, 0xA0, key_spec, hash_algo, "RSASignInteractiveCancel");
	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_rsa_verify_ex(int app_id, int container_id, int key_spec, int hash_algo,
								 unsigned char * input_data, int data_len,
								 unsigned char * signature, int sig_len)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_3_EXT, 0xC0, 0x1E, key_spec, hash_algo, "RSAVerifyEx");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	mk_utility::fill_buff_with_dword_value_be(data_len, data + pos);
	pos += 4;

	memcpy(data + pos, input_data, data_len);
	pos += data_len;

	memcpy(data + pos, signature, sig_len);
	pos += sig_len;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_import_ext_rsa_keypair_head(int app_id, int container_id, int key_spec)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_3_EXT, 0xC0, 0x20, key_spec, 0, "ImportExtRSAKeyPair");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_delete_keypair(int app_id, int container_id, int key_spec)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_3_EXT, 0xC0, 0x22, key_spec, 0, "DeleteKeyPair");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_delete_certificate(int app_id, int container_id, int key_spec)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_3_EXT, 0xC0, 0x24, key_spec, 0, "DeleteCertificate");

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_gen_rsa_keypair_ex(int app_id, int container_id, int key_spec, int bit_len)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0xC0, 0x26, key_spec, 0, "GenRSAKeyPairEx");
	newApdu->set_comm_timeout(MAX_RSA_TIMEOUT);

	unsigned char data[4096] = {0};

	int pos = 0;
	mk_utility::fill_buff_with_word_value_be(app_id, data);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(container_id, data + pos);
	pos += 2;

	mk_utility::fill_buff_with_word_value_be(bit_len, data + pos);
	pos += 2;

	newApdu->set_lc_data(data, pos);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_gen_ext_rsa_keypair(int bits)
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0xC0, 0X80, 1, 1, "GenExtRSAKeyPair");
	newApdu->set_comm_timeout(MAX_RSA_TIMEOUT);

	unsigned char data[32] = {0};

	mk_utility::fill_buff_with_word_value_be(bits, data);

	newApdu->set_lc_data(data, 2);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_export_ext_rsa_pub_key()
{
	apdu * newApdu = new apdu(SC_APDU_CASE_2_EXT, 0xC0, 0X82, 1,0, "ExportExtRSAPubKey");

	return newApdu;

}

apdu * apdu_rsa_manager::create_apdu_import_ext_rsa_keypair_to_ram( unsigned char * keypair_blob, int blob_len )
{
	apdu * newApdu = new apdu(SC_APDU_CASE_3_EXT, 0xC0, 0X84, 1, 0, "ImportExtRsaKeyPairToRam");

	newApdu->set_lc_data(keypair_blob, blob_len);

	return newApdu;
}

apdu * apdu_rsa_manager::create_apdu_ram_rsa_operation( int mode, unsigned char * data, int data_len )
{
	apdu * newApdu = new apdu(SC_APDU_CASE_4_EXT, 0xC0, 0X86, mode, 0, "RSAOperation");

	newApdu->set_lc_data(data, data_len);

	return newApdu;
}
